Gitのフック(pre-commit)とGithubActionsでSnyk Codeによる継続的なコードスキャンを試してみた
こんにちは、AWS事業本部コンサルティング部に所属している今泉(@bun76235104)です。
先日 Snyk Code
とVSCodeの拡張機能でローカル環境で開発中コードのスキャンをやってみました。
実際のところ開発の時点で自分が書いているコードのどこが危険かというフィードバックをもらえることはありがたく、各種IDEで手軽に導入できるので非常に素晴らしいと思います。
今回はチーム開発をする上で、個々人が利用しているIDEに依存せず、SnykCodeを継続的に利用できないか考えて、以下2種類を試してみました!
- git hooksの機能を使ってコミット前にSnyk Code実行
pre-commit
によってコミット前のSnyk Codeによるチェック
- GithubActionsによりコードプッシュ時のSnyk Code実行
なお、今回前準備として以下の設定が終わっていることを前提に話を進めますのでご了承ください。
- gitコマンドのインストール
- Snyk CLIのインストールと設定
snyk code test
コマンドが利用できる状態
git hooksによるコミット前のSnyk Codeによるスキャン
Git - Git フックの機能を活用して、Snyk Codeのチェック非通過の場合はコミットすらできないように設定してみます。
プロジェクトのルートで以下コマンドを実行します。
mkdir .githooks touch .githooks/pre-commit chmod 766 .githhoks/pre-commit
.githooks/pre-commitに以下の内容を書き込みます。
#!/bin/sh snyk code test
snyk code test
のコマンドでは危険なコードが検出されるとステータスコードが1で終了します。
pre-commitでは、ステータスコードが1で終了した場合、変更をコミットすることができなくなりますので、開発者にとってもコミット履歴が綺麗に保てるというメリットがあると思います。
今回は危険度の低いコードでも検出された場合コミットできないので、コマンドにオプションをつけて危険度が高いものだけを対象にしても良いかもしれません。
# オプション --severity-threshold=<low|medium|high|critical> Report only vulnerabilities at the specified level or higher. Note that the Snyk Code configuration issues do not currently use the critical severity level.
例えばhigh以上のレベルだけを対象にする場合はpre-commitで実行させるコマンドを以下の様に書き換えると良いと思います。
snyk code test --severity-threshold=high
次に各開発メンバーが本プロジェクトのルートディレクトリにて、以下コマンドを実施して .githooks/pre-commit の内容をコミット前に実施する様に設定します。
git config --local core.hooksPath .githooks/
試しに脆弱なコードを追加してコミットしようとすると以下の様に表示され、コミットできないことを確認しました。
function dangerCode1() { const url = new URL(window.location.href); const params = url.searchParams; eval(params); } function dangerCode2() { location.href = "/danger/1/show?param=" + param; }
Testing ... ✗ [High] Code Injection Path: ng.js, line 4 Info: Unsanitized input from the document location flows into eval, where it is executed as JavaScript code. This may result in a Code Injection vulnerability. ✔ Test completed Organization: hoge Test type: Static code analysis Project path: hoge Summary; 1 Code issues found 1 [High]
Github Actionsでpush時にSnyk Codeのスキャンを実施する
ワークフローの追加
pre-commitによるSnyk Code実行で検出されたコードがコミットされることは予防できているはずですが、各開発者の設定の不備や、意図的にpre-commitを無効化される可能性があります。
そのため、GithubActionsを利用してsnyk code test
が通らなければ、マージできない様に設定していきます。(今回はコードのプッシュ時に発火するように設定しています)
次にGithubActions用のワークフローを記載します。
# 参考; https://github.com/snyk-labs/nodejs-goof/blob/f985f27f48b00b38c0d2d86f87280bee06fddb0c/.github/workflows/snyk-code.yml#L1 name: "snyk code test" on: [push] jobs: snyk_code_test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: snyk/actions/setup@master - name: Snyk Test run: snyk code test --org=${{ secrets.SNYK_ORG }} continue-on-error: true env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
本変更をリポジトリにプッシュする前に、事前にSnyk Tokenの内容をGithubリポジトリのSecretsに設定する必要があります。
Tokenの取得方法については、こちらの記事が参考になります。
GithubリポジトリへのSecretsの設定方法については、暗号化されたシークレット - GitHub Docsをご参照ください。
SNYK_TOKEN
と共に SNYK_ORG
にOrganizationの識別子も設定してください。
識別子(orgslugname)についてはHow to select the organization to use in the CLI – Support Portal | Snykをご参照ください。
ブランチ保護の設定
以下記事を参考に、ブランチの保護を行います。
Require branches to be up to date before merging
の設定で snyk_code_test
を設定しておきましょう。
GithubActionsを動かしてみた
一時的に pre-commitをコメントアウトして、危険なコード(ng.js)をコミットしてリポジトリにプッシュしてみました。
snyk code test
が終了コード1で終了するため、ワークフローが失敗し、マージできない状態になっています。
Actionsの内容をみてみると、以下の様に検知してくれていることがわかります。
Run snyk code test --org=*** Testing /home/runner/work/snyk-code-pre-commit/snyk-code-pre-commit ... ✗ [High] Code Injection Path: ng.js, line 4 Info: Unsanitized input from the document location flows into eval, where it is executed as JavaScript code. This may result in a Code Injection vulnerability. ✔ Test completed Organization: *** Test type: Static code analysis Project path: /home/runner/work/snyk-code-pre-commit/snyk-code-pre-commit Summary: 1 Code issues found 1 [High] Error: Process completed with exit code 1.
まとめ
今回はgitのフック機能とGithubActionsを利用して、Snyk Codeを実行してみました。
Snykはさまざまなツールとの統合を出してくれているので、これらを使いこなすことでソフトウェア開発の様々なライフサイクルで活躍してくれそうです。
なお、今回は pre-commit
によるタイミングでチェックを行なっていますが、コミット毎にチェックが走るのが辛い場合は pre-push
のタイミングにするなど工夫をすると開発者体験が変わってくると思います。
この記事がどなたかの参考になりますと幸いです。